package lsp;

import java.io.IOException;
import java.net.SocketException;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;

import api.LspParams;
import api.LspServerInterface;

public class LspServer implements LspServerInterface {
	private int port;
	private LspParams params;
	private LinkedBlockingDeque<LspMessage> entrada;
	private ConcurrentHashMap<Short, LspConnection> tabelaDeConexoes;

	public LspServer(int port, LspParams params) throws SocketException {
		this.port = port;
		this.params = params == null ? new LspParams() : params;
		this.entrada = new LinkedBlockingDeque<LspMessage>();
		this.tabelaDeConexoes = new ConcurrentHashMap<Short, LspConnection>();
		Thread inPackageHandlerServer = new Thread(new InPackageHandlerServer(
				this.entrada, this.port, this.tabelaDeConexoes, this.params));
		inPackageHandlerServer.start();
	}

	@Override
	public Pack read() {
		LspMessage mensagem;
		while (true) {
			if (!entrada.isEmpty()) {
				mensagem = this.entrada.pollLast();
				return new Pack(mensagem.getConnId(), mensagem.getPayload());
			}
		}
	}

	@Override
	public void write(Pack pack) throws IOException {
		if (tabelaDeConexoes.containsKey(pack.getConnId())) {
			tabelaDeConexoes.get(pack.getConnId()).enviaData(pack.getPayload());
		} else
			throw new LostConectionException(
					"Cliente nao existente ou com conexao perdida.");
	}

	@Override
	public void closeConn(short connId) {
		LspConnection conexao = this.tabelaDeConexoes.get(connId);
		this.tabelaDeConexoes.remove(connId);
		conexao.close();
	}

	@Override
	public void closeAll() {
		for (Entry<Short, LspConnection> elemento : this.tabelaDeConexoes
				.entrySet()) {
			LspConnection conexao = this.tabelaDeConexoes
					.get(elemento.getKey());
			this.tabelaDeConexoes.remove(elemento.getKey());
			conexao.close();
		}
	}
}
